#ifdef __WIN32__
#include <io.h>
#include <windows.h>
#else
#include <sys/stat.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "db.h"
#include <QApplication>
#include <QDesktopServices>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlDriver>
#include <QDateTime>
#include "debug.hpp"
#include "qtq_config.h"
#include "debug.hpp"
#include <QDir>
#include <QMutex>
#include <QVariant>
#include <vector>
#include "util.hpp"
#include "qqclient.hpp"
extern qqclient* qq;
std::vector<Status> g_StatusChange;
std::vector<qqqun*> g_QunUpdates;
QunMemberRecords gQunMemberRecords;
InfoRecords gAllInfoRecords; //所有消息暂存
GroupByUIdInfoRecords gGoupedInforecords;//分组信息暂存
MsgQueque gMsgQueque; //消息队列
db db::instance; //sington;
db::db():
m_PageSize(50),
lastUid(0)
{


}
db::~db()
{
    DBG( "db::~db()" );
    if (m_db.isOpen())
           m_db.close();
}
void db::close()
{
    m_db.close();
}
bool db::open(uint uid)
{
    bool needReopen = false;
    if(lastUid != uid)
    {
        lastUid = uid;
        needReopen = true;
    }

    if(m_db.isOpen() && needReopen == false)
        return true;
    DBG( "db::open() start" );
#ifdef __SYMBIAN32__
    QString DataRootDir = "e:/data/aenqq";
#else
    QString DataRootDir = QDesktopServices::storageLocation( QDesktopServices::DataLocation );
#endif
    DataRootDir = QDir::toNativeSeparators(DataRootDir);
    QString usersDir = DataRootDir.append(QDir::separator()).append("users");
    QString userDBDir(usersDir);
    userDBDir.append(QDir::separator()).append(QString("%1").arg(uid)).append(QDir::separator());
    userDBDir = QDir::toNativeSeparators(userDBDir);

    QString userDbFile(usersDir);
    if(uid == 0)
        userDbFile.append(QDir::separator()).append(QString("%1").arg(uid)).append(QDir::separator()).append("Info_v8.db");
    else
        userDbFile.append(QDir::separator()).append(QString("%1").arg(uid)).append(QDir::separator()).append("Info_v10.db");

    userDbFile = QDir::toNativeSeparators(userDbFile);

    DBG_QS( usersDir ) ;
    DBG_QS( userDBDir ) ;
    DBG_QS( userDbFile );

    // mkdir if not exist
    QByteArray ba = userDBDir.toLatin1();
	{
	 QDir qdir(userDBDir);
	 qdir.mkpath(userDBDir);
	}
    
    ba =  userDbFile.toLatin1();
    char* dbfile = ba.data();
    //create db if not exist
    bool needinittable = false;
	QFileInfo fi(userDbFile);
	if( !fi.exists( )){
        DBG( "db(%s) not exist,need create",dbfile );
        needinittable = true;
        QFile f(userDbFile);
        if (!f.open(QIODevice::WriteOnly))
        {
            DBG( "Can not create db:%s",dbfile );
            return false;
        }
        f.close();
    }
    // OpenDB

    // Find QSLite driver

    m_db = QSqlDatabase::addDatabase("QSQLITE");
    // http://doc.trolltech.com/4.5/sql-driver.html#qsqlite
    m_db.setDatabaseName(userDbFile);
    // Open databasee
    bool isSucess = m_db.open();  //尝试连接数据库
    if(!isSucess)
    {
        QString erroInfo = QString("db_lastError:%1").arg( m_db.lastError().text());
        DBG_QS( erroInfo );
    }

    if(needinittable)
    {
        DBG( "need init tables");
        if(m_db.isOpen())
        {
            QSqlQuery* query = new QSqlQuery();
            query->exec("create table inforecord(id INTEGER PRIMARY KEY AUTOINCREMENT,fromid int,toid int,toqunid,createtime int,info text,int type )");
            query->exec("create index inforecord_idx on inforecord(fromid,toid,toqunid,createtime)");
            if(query->isValid())
                DBG( "inforecord table init ok" );
        }
        if(m_db.isOpen())
        {
            QSqlQuery* query = new QSqlQuery();
            query->exec("create table settings(id INTEGER PRIMARY KEY AUTOINCREMENT,key varchar(50) ,svalue varchar(50),info text )");
            query->exec("create index settings_idx on settings(key)");
            if(query->isValid())
                DBG( "settings table init ok" );
        }
        if(m_db.isOpen())
        {
            QSqlQuery* query = new QSqlQuery();
            query->exec("create table groups(id INTEGER PRIMARY KEY AUTOINCREMENT,number int, name varchar(50) ,info text )");
            if(query->isValid())
                 DBG( "group table init ok" );
        }
        if(m_db.isOpen())
        {
            QSqlQuery* query = new QSqlQuery();
            query->exec("create table buddy(id INTEGER PRIMARY KEY AUTOINCREMENT,number int, name varchar(50),face int,age int,sex int gid int,qqshow int,flag int,session_key varchar(16),status int, version int, verify_flag int,sign_time int,account_flag int )");
            query->exec("create unique index buddy_idx on buddy(number);");
            if(query->isValid())
                DBG( "buddy table init ok" );
        }
        if(m_db.isOpen())
        {
            QSqlQuery* query = new QSqlQuery();
            query->exec("create table qun(id INTEGER PRIMARY KEY AUTOINCREMENT,number int, name varchar(50),info text )");
            if(query->isValid())
                DBG( "qun table init ok" );
        }
        if(m_db.isOpen())
        {
            QSqlQuery* query = new QSqlQuery();
            query->exec("create table qunmember(id INTEGER PRIMARY KEY AUTOINCREMENT,qun_id int ,number int, name varchar(50),face int,ageint,sex int,qqshow int,flag int,status int,account_flag int,account varchar(64),role int,org int )");
            query->exec("create unique index qun_member_idx on qunmember(qun_id,number);");
            if(query->isValid())
                DBG( "qun table init ok" );
        }
    }

    DBG( "db::open end");
    return isSucess;
}
void db::BeginTrans()
{
    this->m_db.transaction();
}

void db::Commit()
{
    this->m_db.commit();
}
void db::pushMemberInfo(STR_qunmember &qm)
{
    mutex_qunmember.lock();
    gQunMemberRecords.push_back(qm);
    mutex_qunmember.unlock();
}
void db::pushQun(qqqun* q)
{
    mutex_qun.lock();;
    g_QunUpdates.push_back(q);
    mutex_qun.unlock();
}

void db::pushRecord(uint type,uint friendId,STR_inforecord &info)
{
    QMutexLocker ql(&mutex_chat);
    if(info.fromid != qq->number ) //如果不是自己发送的信息
    {
        InfoRecords *iRecords;
        if(gGoupedInforecords.find(friendId) == gGoupedInforecords.end())
        {
            iRecords = new InfoRecords();
            gGoupedInforecords[friendId] = iRecords;
            infoqueque q;
            q.number = friendId;
            q.type = type;
            gMsgQueque.push(q);
        }
        else
        {
            iRecords = gGoupedInforecords[friendId];
        }
        iRecords->push_back(info);        
    }
    gAllInfoRecords.push_back(info);
}
void db::procRecord(uint friendId)
{

}

bool db::writeAccount(QString& uid,QString &pwd)
{
    mutex_db.lock();
    if(m_db.isOpen())
      {
        QSqlQuery query;
        QString sql="";
        QString checkSql = QString("select * from settings where key='lastuid' and svalue like '%1%'").arg(uid);
        query.exec(checkSql);
        if(query.next())
        {
            sql = QString("update settings set svalue='%1\t%2' where key='lastuid' and svalue like '%3%%'" ).arg(uid).arg(pwd).arg(uid);
        }
        else
        {
            sql = QString("insert into settings(key,svalue) values('lastuid','%1\t%2')").arg(uid).arg(pwd);
        }
        DBG_QS(sql);
        query.exec(sql);
    }

    mutex_db.unlock();
    return true;
}
void db::readAccount( AccountList &accountList )
{
    mutex_db.lock();
    if(m_db.isOpen())
    {
        QSqlQuery query;//(m_db);
        query.exec(QString("select * from settings where key='lastuid'"));
        DBG( "numRowsAffected:%d", query.numRowsAffected() );
        while(query.next())
        {
            QString value = query.value(2).toString();
            accountList.push_back(value);
        }
    }
    else
    {
        DBG("db has not open");
    }
    mutex_db.unlock();

}
bool db::getQunMemberName(uint qun_number,uint number,char *name)
{
    mutex_db.lock();
    //DBG("getQunMemberName start");
    bool ret = false;
    if (m_db.isOpen())
    {
        QString sql = QString("select * from qunmember where qun_id='%1' and number='%2'").arg(qun_number).arg(number);
        //DBG_QS( sql );
        QSqlQuery query;
        query.exec(sql);
        ret = query.next();
        if(ret)
        {
            /*QString erroInfo = QString("getQunMemberName done!numRowsAffected:%1").arg(ret);
            DBG_QS( erroInfo );
            qDebug() << query.value(0).toString();
            qDebug() << query.value(1).toString();
            qDebug() << query.value(2).toString();*/
            strcpy(name,query.value(3).toByteArray().data());
        }
        else
        {
            sprintf(name,"%d",number);
        }

    }
    else
    {
        DBG("db has not open");
    }
    mutex_db.unlock();
    return ret;
}

bool db::writeQunMember(uint qun_number,uint number,const char* name)
{
    mutex_db.lock();
    //DBG("writeQunMember start");
    bool ret = false;
    if (m_db.isOpen())
    {
        QString sql = QString("insert into qunmember(id,qun_id,number,name) values(null,'%1','%2','%3')").arg(qun_number).arg(number).arg(name);
        //DBG_QS( sql );
        QSqlQuery query;
        query.exec(sql);
        ret = query.numRowsAffected();
        //QString erroInfo = QString("writeQunMember done!numRowsAffected:%1").arg(ret);
        //DBG_QS( erroInfo );
    }
    else
    {
        DBG("db has not open");
    }
    mutex_db.unlock();
    return ret;
}

bool db::writeRecord(uint type,uint &fromid,uint &toid, uint toqunid,uint time,QString& info)
{
    mutex_db.lock();
    DBG("writeRecord start");
    bool ret = false;
    if (m_db.isOpen())
    {
        QString sql = QString("insert into inforecord values(null,'%1','%2','%3','%4','%5','%6')").arg(fromid).arg(toid).arg(toqunid).arg(time).arg(info).arg(type);
        DBG_QS( sql );
        QSqlQuery query;
        query.exec(sql);
        ret = query.numRowsAffected();
        QString erroInfo = QString("writeRecord done!numRowsAffected:%1").arg(ret);
        DBG_QS( erroInfo );
    }
    else
    {
        DBG("db has not open");
    }
    mutex_db.unlock();
    return ret;
}

uint db::getRecordPageCount()
{
    mutex_db.lock();
    uint count = 0;
    QSqlQuery query;//(m_db);
    query.exec(QString("select count(*) from inforecord where toid = '%1'").arg(m_UID));
    if(!query.exec())
    {
        count = query.value(0).toUInt();
    }
    mutex_db.unlock();
    return count;

}

void db::setRecordPageSize(uint pageSize)
{
    m_PageSize = pageSize;
}

uint db::readRecord(InfoRecords& infoRecords, uint ownerId,uint uid,uint type, uint pageIndex)
{
    mutex_db.lock();
    uint ret =0;
    if(m_db.isOpen())
    {
        QString sql;
        if(type == 0)
        {

            sql = QString("select * from inforecord where (fromid = '%1' and  toid= '%2') or (fromid = '%3' and  toid= '%4') order by createtime desc,id desc limit %5,%6").arg(ownerId).arg(uid).arg(uid).arg(ownerId).arg(pageIndex).arg(m_PageSize);
        }
        else
            sql = QString("select * from inforecord where toqunid= '%1' order by createtime desc,id desc limit %2,%3").arg(uid).arg(pageIndex).arg(m_PageSize);
        QSqlQuery query(sql);

        DBG_QS( sql );
        infoRecords.clear();
        while(query.next())
        {
            ret ++;
            STR_inforecord record;
            record.fromid = query.value(1).toInt();
            record.toid = query.value(2).toInt();
            record.toqunid = query.value(3).toInt();
            record.time = query.value(4).toInt();
            record.info = query.value(5).toString();
            infoRecords.push_back(record);
        }

    }
    mutex_db.unlock();;
    return ret;

}
